/***********************************************************************
* ******************************************************************** *
* *																					 	* *		
* *   RAMONLYBIOS.C                                                  * *
* *																					 	* *		
* * 	Copyright (c)  2001 Z-World.												* *		
* *																					 	* *		
* *	Special BIOS for Rabbit 2000 based boards which have RAM only, * *		
* *	no flash. RAM only boards are not currently manufactured by    * *		
* *	Z-World, but some Rabbit/Z-World customers make RAM only       * *
* *   boards.                                                        * *		
* *																						* *							
* *	THIS BIOS WILL NOT WORK ON ANY Z-WORLD/RABBIT SEMICONDUCTOR    * *
* *	BOARD LEVEL PRODUCT WITHOUT MODIFICATIONS TO THE HARDWARE      * *
* *	This is NOT for compiling to RAM on an off-the-shelf product.  * *
* *	This is for custom boards which have no flash and have RAM     * *
* *	connected to CS0/OE0/WE0                                       * *
* *																						* *							
* *	A SPECIAL COLDLOADER BINARY IMAGE IS ALSO REQUIRED FOR RAM     * *
* *	ONLY BOARDS. USE RAMONLYCOLDLOAD.BIN                           * *
* *																						* *							
* *	To use RAMONLYLOADER.BIN, change the name of                   * *
* *   BIOS\COLDLOAD.BIN  to to COLDLOAD.BAK, and rename              * *
* *   BIOS\RAMONLYCOLDLOAD.BIN to COLDLOAD.BIN. Do not forget to     * *                         
* *	reverse this change if you revert to a board with standard     * *		
* *   memory configuration.                                          * *						
* *																					 	* *		
* ******************************************************************** *
************************************************************************/

#ifndef __BIOS_ALREADY_COMPILED
	#define __BIOS_ALREADY_COMPILED
#else
	#fatal "Can not compile the BIOS as a user program!"
#endif

/////// BEGIN USER MODIFIABLE MACROS /////////////////////////////////

//***** Miscellaneous Information *******************************************
#define PRODUCT_NAME	"Universal Rabbit BIOS Version 7.05RO"	

#define CLOCK_DOUBLED 1				// Set to 1 to double clock if XTAL<=12.9MHz,
											//  or to 0 to always disable clock doubler
 
#define CS1_ALWAYS_ON  0         // Keeping CS1 active is useful if your
                                 // system is pushing the limits of RAM
                                 // access time. It will increase power
                                 // consumption a little. Set to 0 to
                                 // disable, 1 to enable
											                                                                     
//***** File System Information *******************************************
#define FS2_RAM_RESERVE 0			//  Number of 4096-byte blocks to reserve for
											//  filesystem II battery-backed RAM extent.
											//  Leave this at zero if not using RAM filesystem.

//***** Error Logging information *******************************************
#define ENABLE_ERROR_LOGGING   0 // Enable error logging, set to 1 to enable

//***** Memory mapping information ************************************
#define DATAORG      0x6000      // Begining logical address for data seg.
                                 // A user with a lot of root code
                                 // and not alot of root data can increase
                                 // this in increments of 0x1000 to as high
                                 // as 0xB000 to allow more root code space.
                                 // OR, root data space can be increased by
                                 // lowering this to as low as 0x3000.

#if (_RAM_SIZE_==0x80)           // Number of 4k pages of RAM. _RAM_SIZE_  
#define RAM_SIZE 0x40            // is defined internally by Dynamic C
#else										// during the coldboot stage, but can
#define RAM_SIZE _RAM_SIZE_      // changed here. If _RAM_SIZE_ is 0x80 (512K)
#endif                           // we reserve the upper half for xalloc
                                 // and map top of DATA to the top of the
                                 // lower half of RAM. The xalloc initialization
                                 // code will recognize that the space is
                                 // available if RAM_SIZE < _RAM_SIZE_.

#define FLASH_SIZE 0             // Number of 4k pages of flash. _FLASH_SIZE_  
                                 // is defined internally by Dynamic C during
                                 // the coldboot stage by reading the flash ID
                                 // int from the flash on CS0, but can changed
			          				   // here.


#define WATCHCODESIZE    0x200   // Number of root RAM bytes for Watch Code

//********************************************************************
//  Advanced configuration items follow
//  (Primarily of interest to board makers)
//********************************************************************

//***** Starting 4k page for RAM physical addresses *******************
#define RAM_START       0x0      //	RAM starts at 00000 if compiling to RAM 

//***** Wait States for the memory devices ****************************
#define NUM_RAM_WAITST	 0       
#define NUM_CS2_WAITST   0

//***** Chip selects/write enables for the memory devices *************
#define CS_RAM				0x00	  // CS0/OE0/WE0	

//***** Inversion bits for bank control registers *********************
#define MB0CR_INVRT_A18  0
#define MB1CR_INVRT_A18  0
#define MB2CR_INVRT_A18  0
#define MB3CR_INVRT_A18  0
#define MB0CR_INVRT_A19  0
#define MB1CR_INVRT_A19  0
#define MB2CR_INVRT_A19  0
#define MB3CR_INVRT_A19  0

////////// END OF USER-MODIFIABLE MACROS /////////////////////////////////

#define XMEM_RESERVE_SIZE 0x0000L 
#define ENABLECLONING    0
#define FLASH_BUF_SIZE   0L
#define FLASH_BUF_PHYS   0L
#ifdef _FLASH_
#undef _FLASH_
#define _RAM_ 1
#endif

struct _regBuffer {
	unsigned _AF;
	unsigned _BC;
	unsigned _DE;
	unsigned _HL;
	unsigned _SP;
	unsigned _PC;
	unsigned _XPC;
	unsigned _IX;
	unsigned _IY;
	unsigned _AFprime;
	unsigned _BCprime;
	unsigned _DEprime;
	unsigned _HLprime;	
};

typedef struct {
	unsigned short addr;  // address
	unsigned char base;   // base (BBR or CBR)
}	ADDR24_S;

typedef union { unsigned long l;    // long for increment/decrement 
					struct { ADDR24_S a; // the address itself 
								char flags; // flags associated 
						 } aaa;
}	ADDR24;


#define USE115KBAUD   _USE115KBAUD_				// _USE115KBAUD_ set internally by DC

//***** Settings for bank control registers ***************************
#define MB0CR_SETTING	RAM_WSTATES | CS_RAM | (MB0CR_INVRT_A18<<4) | (MB0CR_INVRT_A19<<5)
#define MB1CR_SETTING	RAM_WSTATES | CS_RAM | (MB1CR_INVRT_A18<<4) | (MB1CR_INVRT_A19<<5)
#define MB2CR_SETTING	RAM_WSTATES | CS_RAM | (MB2CR_INVRT_A18<<4) | (MB2CR_INVRT_A19<<5)
#define MB3CR_SETTING	RAM_WSTATES | CS_RAM | (MB3CR_INVRT_A18<<4) | (MB3CR_INVRT_A19<<5)

#define STACKORG  		0xD000	// Begining logical address for stack segment

//***** Compute the MMU segment registers *****
//***** the 1 represents space for a 4K flash transfer buffer
#define DATASEGVAL   RAM_START + RAM_SIZE - (STACKORG>>12)

#define XMEMSEGVAL	(0xff & ((DATAORG-0xe000)/4096))

#define MEMBREAK    0+(STACKORG/256) + (DATAORG/4096)  // SEGSIZE reg value


//***** Compute Code and Data ORGs ************************************
#ifndef FS_RESERVE_SIZE
#define FS_RESERVE_SIZE 0	// default to no space reserved for the FS in the first flash
#endif
#define WATCHCODEORG 	STACKORG-(0x0200+WATCHCODESIZE)
#define ROOTCODEORG  	0x0000
#define XMEMORYORG   	0xE000

#define XMEMORYSIZE   	RAM_SIZE*4096L-0xE000

#define ROOTCODESIZE  	DATAORG   
#define ROOTDATAORG  	WATCHCODEORG-0x0001
#define ROOTDATASIZE  	STACKORG-(DATAORG+0x200+WATCHCODESIZE)

/* marker for where the end of XMEM is */
#define END_OF_XMEMORY	(((XMEMSEGVAL<<12L)+(long)XMEMORYORG+(long)XMEMORYSIZE)&0xFFFFF)

//***** This is to let Dynamic C programs know we are running in Flash or RAM.
//***** _RAM_, and _FLASH_ are defined by the compiler.  RUN_IN_RAM
//***** predates these compiler generated macros.
#define RUN_IN_RAM 1

//***** Tell the compiler this is a BIOS 
#pragma Rabbit CompileBIOS 	

/*-------------------------------------------------------------------
**  CODE ORG statements to determine code locations in physical and
**  logical memory space.
**
**  Type Name     Segment       Bottom       Size			  	   Use
--------------------------------------------------------------------*/
#rcodorg rootcode	0x00          ROOTCODEORG  ROOTCODESIZE		apply
#xcodorg xmemcode	(XMEMSEGVAL)  XMEMORYORG   XMEMORYSIZE       apply
#wcodorg	watcode  (DATASEGVAL)  WATCHCODEORG WATCHCODESIZE     apply

/*--------------------------------------------------------------------
**  DATA ORG statements to determine data locations in physical and
**  logical memory space.
**
**  Type Name     Segment        Top          Size			  	 Use
-------------------------------------------------------------------*/
#rvarorg rootdata	(DATASEGVAL) 	ROOTDATAORG  ROOTDATASIZE 	 apply


//**** internal and external vector table locations *****************
#define XINTVEC_BASE  STACKORG-0x100
#define INTVEC_BASE STACKORG-0x200


/************************** LOGICAL MEMORY MAP **********************

  FFFF                          ---------------			
                                |             |
                                |             |
                                ~             ~
                                     Xmem
                                ~             ~
                                |             |
                                |             |
  E000                          ---------------
                                | Stack Top   |
                                |             |
                                ~             ~
                                     Stack
                                ~             ~
                                |             |
                                |             |
  STACKORG                      ---------------	
                                | external    |
                                | vector tabl.|
  STACKORG-100h                 ---------------				
                                | internal    |
                                | vector tabl.|
  STACKORG-200h                 ---------------
                                |     |       |
                                |    /|\      |
                                |     |       |
                                ~             ~
                                  Watch Code
                                ~             ~
                                |     |       |
                                |    \|/      |
   WATCHCODEORG                 |     |       |
                                ---------------
   ROOTDATAORG                  |     |       |
                                |    /|\      |
                                |     |       |
                                ~             ~
                                   Root Data
                                ~             ~
                                |     |       |
                                |    \|/      |
                                |     |       |
                                ---------------
                                |     |       |
                                |    /|\      |
                                |     |       |
                                ~             ~
                                   Root Code
                                ~             ~
                                |     |       |
                                |    \|/      |
                                |     |       |
  ROOTCODEORG (0000)            ---------------
    
*******************************************************************/


//***** Libraries needed by the BIOS *********************************
#use BIOSFSM.LIB 						// The communication Finite State Machine
#use SYSIO.LIB 						// IO register assignemnts and functions
#use DBUGKERN.LIB						// The debug kernel
#use CSUPPORT.lib						// Some C support functions
#use STACK.lib							// The stack initialization functions
#use IDBLOCK.LIB						// Flash ID block access fcns (and CRC).
#use ERRORS.LIB						// Runtime error handling

/********************************************************************
*********************************************************************
*
*	BIOS internals follow
*
*********************************************************************
*********************************************************************/

#if (NUM_RAM_WAITST==0)
#define RAM_WSTATES 0xc0
#else
#if (NUM_RAM_WAITST==1)
#define RAM_WSTATES 0x80
#else
#if (NUM_RAM_WAITST==2)
#define RAM_WSTATES 0x40
#else
#if (NUM_RAM_WAITST==4)
#define RAM_WSTATES 0x00
#endif
#endif
#endif
#endif

#if (NUM_CS2_WAITST==0)
#define CS2_WSTATES 0xc0
#else
#if (NUM_CS2_WAITST==1)
#define CS2_WSTATES 0x80
#else
#if (NUM_CS2_WAITST==2)
#define CS2_WSTATES 0x40
#else
#if (NUM_CS2_WAITST==4)
#define CS2_WSTATES 0x00
#endif
#endif
#endif
#endif

#define SIZESTDIOBUFF 130

#define HW_MEMBREAK 0xe2

/*** end of macro definitions */

/*** variable definitions */
#define BIOSSTACKSIZE 40
char dbXPC;

void *dkcState;			//	the address (state) of  debugger kernel comm machine
char BiosStack[BIOSSTACKSIZE]; // initial stack for bios in data the segment
char commBuffer[256];	//	communication buffer
char stdioCommBuff[SIZESTDIOBUFF];
char watchBuffer[8];		//	buffer for watch expression results

struct _fcTable fcTable;			//	RAM location to store the fctable
char stepRelay[3];		//	ram location for rst28 relay

struct _dcParam DCParam;

struct _DCSrcDebug DCSrcDebug;
char  OPMODE, _dkfirst, cloningNow;

/*** do not change the order of definition */
struct _dkControl dkControlFlags;
struct _regBuffer registers;			//	RAM location to store the registers
char _dkenable28,_dkdisable28; 		// byte to store at RST28 enable, disable
int _SectorSize;
char	freq_divider;						// time constant for 19200 baud

// store value of GCSR register to determine reset reason
char	reset_status;					

// the internal I/O registers -the shadows
// parallel ports
char PADRShadow, PBDRShadow, PCDRShadow, PCFRShadow;
char PDDRShadow, PDCRShadow, PDFRShadow, PDDCRShadow, PDDDRShadow;
char PEDRShadow, PECRShadow, PEFRShadow, PEDDRShadow;

char GCSRShadow; 	// global control status register
char GOCRShadow; 	// global control
char GCDRShadow; 	// clock doubler

char MMIDRShadow; // memory management aux reg
char MB3CRShadow, MB2CRShadow, MB1CRShadow, MB0CRShadow; // mem bank cntrl regs
char IB0CRShadow, IB1CRShadow, IB2CRShadow, IB3CRShadow, IB4CRShadow, 
     IB5CRShadow, IB6CRShadow, IB7CRShadow;
char I0CRShadow, I1CRShadow;
char TACSRShadow, TACRShadow, TAT1RShadow, TAT4RShadow, TAT5RShadow,
	  TAT6RShadow, TAT7RShadow;
char TBCSRShadow, TBCRShadow;
char SPCRShadow, SACRShadow, SBCRShadow, SCCRShadow, SDCRShadow;

char NewPrintConFlag;

struct progStruct {
	ADDR24      RCB,RCE,    // root code (Begin and End)
					XCB,XCE,    // extended code (Begin and End)
					RDB,RDE,    // root data (Begin and End)
					XDB,XDE;		// extended data (RAM) (Begin and End)
	unsigned short  auxStkB,// aux stack Begin
					auxStkE,    // end
					stkB,       // stack begin
					stkE,       // end
					freeB,      // free begin
					freeE,      // end
					heapB,      // heap begin
					heapE;      // end
	}; 

extern struct progStruct prog_param;

/*** end of contiguous definition */

/*** end of variable definitions */
/*Begin Header prototypes**************/
 root void biosmain();
 root void dkInit();
 root void WaitSettle();
 root void dkInitTC();
 root void dkWriteMem();
 root void dkSerialISR();
 root void dkReadProgPort();
 root void dkWriteProgPort();
 root void divider19200();
 root void dkInitFCTable();
 root void dkDoMsg();
 root void __bp_init();
 root void dkBPInit();
 root void _xexit2();
 root void _xexit();
 root void dkSetIntVecTabP();
 root void dkSetIntVecTabR();
 root void dkStartup();
 root void dkEnd();
 root void symTab();
 root void AUX_STACK_LIMIT();
 root void AUX_STACK_PTR();
 root void STACK_LIMIT();
 root void symTabEnd();
/*End Header***************************/
#ifndef _TARGETLESS_COMPILE_
#define _TARGETLESS_COMPILE_ 0
#endif
#if (NUM_RAM_WAITST!=0)
#pragma DATAWAITSUSED on
#endif
#asm nodebug
biosmain::
// don't insert any code inbetween this label and the jp
// or the jp and the dw!!!
	jp		InRAMNow		;	jump to debugger kernel start up code
	dw		fcTable		;	pointer to the RAM-based fcTable	
divider19200::
#if _TARGETLESS_COMPILE_ == 1
	db 	_FREQ_DIV_19200_
#else
	db		00h			;  frequency divider for 19200 baud (value from coldloader)
#endif
loaderParameters:
	dw		BIOSCodeEnd	;	store BIOS size, RAM start location, and
	dw		InRAMNow    ;  dkBPInit entry point for use by loading utility.
	dw		dkBPInit

//*** THese aren't used in this BIOS
ErrLogConfiguration::
	dw 	0,0,0,0,0,0,0
ErrLogLastHeader::
	dw 	0,0,0,0,0,0
	dw 	0,0,0,0,0,0,0
I_am_a_fast_clone::
	dw    0

InRAMNow::
	ld		hl,0x4001 	; reset BIOS flag
	xor   a
	ld    (I_am_a_fast_clone),a
	ld		(hl),a

	;; get frequency divider for 19200 baud from where coldloader stored it in RAM
	ld		a, (04002h)			; get FREQADDR, xtal frequency/0.6144MHz (from coldload)
	ld		(divider19200), a	; save in BIOS so it will be saved to flash

	ipset 3

//****** a slight delay for things to settle
	ld    b,50
	ld    de,0e8h        ; the upper 3 bits turn over every 1/1024 s
	ld    h,0
oloop:
	ld    a, 0x5a
	ioi 	ld (WDTCR),a	
	ld		a,0ffh			;write any value to 0r to capture count
	ioi	ld (RTC0R),a
	ld		iy,RTC0R
	ioi	ld L,(iy)
	and   hl,de
loop:	
	ld		a,0ffh			;capture and compare
	ioi	ld (RTC0R),a
	ld		iy,RTC0R
	ioi	ld a,(iy)
	and   e
	cp    L
	jr    z,loop
	djnz  oloop         ; loop until the first value reached  

	; set STATUS pin low and CLK pin off
	ld		a,0xA0
	ioi 	ld		(GOCR),a
	ld		a,00001000b		;	normal oscilator, processor and peri.
								;	from main clock, no periodic interrupt
	ioi   ld	(GCSR),a

#if (CLOCK_DOUBLED == 1)
	ld		a, (divider19200)
	cp		22					; 21 * 0.6144 = 12.9MHz (doubling cutoff)
	jr		c, canDouble2
	xor	a
	jr		setGCDR2
canDouble2:
	ld		a, 07h			; 20ns nominal Low time, best for osc < 14MHz
setGCDR2:
#else
	xor	a					; user says clock not doubled
#endif
	ioi	ld (GCDR), a	; if nonzero, clock is doubled

dkSetMMU:
	ld 	a,MEMBREAK
	ioi 	ld (SEGSIZE), a
	ld 	a, DATASEGVAL
	ioi 	ld (DATASEG), a	

#if (CS1_ALWAYS_ON==0)
	xor 	a
#else	
	ld 	a, 0x10
#endif
	ioi 	ld (MMIDR),a

	;; set up temporary stack in RAM
	ld		hl, BiosStack
	ld		de, BIOSSTACKSIZE-1
	add	hl, de
	ld		sp, hl

	ld 	a, MB0CR_SETTING
	ioi 	ld (MB0CR),a
	ld 	a, MB1CR_SETTING
	ioi 	ld (MB1CR),a
	ld 	a, RAM_WSTATES | CS_RAM
	ioi 	ld (MB2CR),a
	ld 	a, RAM_WSTATES | CS_RAM
	ioi 	ld (MB3CR),a

	ld 	a, MB0CR_SETTING
	ld 	hl,MB0CRShadow
	ld    (hl),a
	ld 	a, MB1CR_SETTING
	ld 	hl,MB1CRShadow
	ld    (hl),a
	ld 	a, RAM_WSTATES | CS_RAM
	ld 	hl,MB2CRShadow
	ld    (hl),a
	ld 	a, RAM_WSTATES | CS_RAM
	ld 	hl,MB3CRShadow
	ld    (hl),a

	// this will disable the flash,
	// everything mapped to RAM now.
	ld 	a, MB2CR_SETTING
	ioi 	ld (MB2CR),a
	ld 	a, MB3CR_SETTING
	ioi 	ld (MB3CR),a

#if (CS1_ALWAYS_ON==0)
	xor 	a
#else	
	ld 	a, 0x10
#endif
	ld 	hl,MMIDRShadow
	ld    (hl),a
	ld 	a, RAM_WSTATES   | 0x05 | (MB2CR_INVRT_A18<<4) | (MB2CR_INVRT_A19<<5)   
	ld 	hl,MB2CRShadow
	ld    (hl),a
	ld 	a, RAM_WSTATES   | 0x05 | (MB3CR_INVRT_A18<<4) | (MB3CR_INVRT_A19<<5)   
	ld 	hl,MB3CRShadow
	ld    (hl),a


	; set STATUS pin low and CLK pin off
	ld		a, 0xA0
	ld		hl, GOCRShadow
	ld		(hl), a

	ld		a,00001000b			;	normal oscilator, processor and peri.
	ld 	hl, GCSRShadow
	ld    (hl), a

#if (CLOCK_DOUBLED == 1)
	ld		a, (divider19200)
	cp		22					; 21 * 0.6144 = 12.9MHz (doubling cutoff)
	jr		c, canDouble3
	xor	a
	jr		setGCDR3
canDouble3:
	ld		a, 07h			; 20ns nominal Low time, best for osc < 14MHz
setGCDR3:
#else
	xor	a					; user says clock not doubled
#endif
	ld		hl, GCDRShadow
	ld		(hl), a
	ld		a, 0c0h
	ioi	ld (PCFR), a	; as initialized in pilot
	ld 	hl, PCFRShadow	
	ld    (hl), a			

	ld    a,0xA0h
	ld		(statusPinState),a
	
	ld 	a,88h
	ld   	(OPMODE),a

	ld 	a,0
	ld   	(_dkfirst),a

	ld 	hl, cloningNow
	ld    (hl), 0x00

	ld b,SIZESTDIOBUFF
	ld hl,stdioCommBuff
clear_stdio:	
	ld (hl),0
	inc hl
	djnz clear_stdio

dkSetTimer:

	;	initialize baud rate generator
	;	for main clock at 8MHz, the calculation follows:
	;	timer A4 to clock serial port A
	;	timer A5 to clock serial port B
	;	timer A6 to clock serial port C
	;	timer A7 to clock serial port D

	;	make timers tick
	ld 	a, 00000001b
	ioi 	ld (TACSR),a
	ld 	hl,TACSRShadow
	ld    (hl),a

	;	make timer A4 clocked by main clock
	;	disable interrupt
	ld 	a, 00000000b
	ioi 	ld (TACR),a
	ld 	hl,TACRShadow
	ld    (hl),a

	;	Read the time constant for 19200 baud calculated by the coldloader...
	ld		a, (divider19200)
	ld		b, a
checkDoubled:
 ;; is clock doubled?
	ld		a, (GCDRShadow)	; get clock doubler register
	or		a
	jr		z, checkDiv			; if zero, clock not doubled
	sla	b						; if clock doubled, multiply constant by two
checkDiv:
 ;; is clock divided by eight?
	ld		a, (GCSRShadow)	; get global control/status register
	and	018h					; mask off unnecessary bits
	jr		nz, saveFreq		; if nonzero, periph clock not divided by 8
	srl	b
	srl	b						; divide by eight
	srl	b
saveFreq:
	ld		a, b
	ld		(freq_divider), a	; save for later use	

setDCbaudrate:
  ;; set up proper baud rate for Dynamic C communication by doing some
  ;; 		fixed-point arithmetic to get 57600 rate (= 19200 rate / 3)
	ld		c, 0					; bc = FREQADDR (b = integer part, c = fraction)
	ld		de, 055h				; de = ~1/3
	mul							; multiply it out
	ld		c, l					; keep integer part
	inc	c						; round up since 055h is actually slightly less than 1/3

check115k:
#if (USE115KBAUD==1)
	srl   c					 	; if 115200 baud wanted, divide by two
#endif

setBaudRate:
	dec	c						; put divider-1 into timer scaling registers
	ld		a, c
	ioi	ld (TAT4R),a		; save scaledown for 57600 baud
	ld 	hl,TAT4RShadow
	ld    (hl),a

;******************************************************************************
; Enter here for sofware reset requested by Dynamic C
; to turn off periodic interrupt
dkInit::
	ipset 3	
	ld		a,00001000b		;	normal oscilator, processor and peri.
								;	from main clock, no periodic interrupt
	ioi   ld	(GCSR),a

;*******************************************************************************

	;	initialize comm ports now
	;	at port a, async, 8-bit, interrupt priority 1
	; make sure other serial ports are disabled
	ld		a, 0x00
	ioi	ld (SBCR), a
	ioi	ld (SCCR), a
	ioi	ld (SDCR), a
	ld		a, 0x01
	ioi 	ld (SACR),a
	ld 	hl,SACRShadow
	ld    (hl),a

dkSetSP:
	ld		hl,BiosStack			; Set up a temporary stack to perform call.
	ld    de,BIOSSTACKSIZE-1   ; Note that stack segment register is not setup here,
	add    hl,de					; but in _ProgStkSwitch.  _ProgStkSwitch is normally
	ld		sp,hl						; called in premain after stack alloc init.
	xor	a  						; zero the xpc
	ld    xpc,a

dkSetComm:
	ld		hl,dkcIState
	ld		(dkcState),hl		;	move to initial state
	call	dkInitTC
	call	dkSetIntVecTabP

dkSetProgPort:
	;	parallel port D, bit 6,0 as output lines
	ld		a,0xc3		;	jump instruction
	ld		(INTVEC_BASE+SERA_OFS),a
	ld		hl,dkSerialISR
	ld		(INTVEC_BASE+SERA_OFS+1),hl

	// initialize registers that come up in unknown states
	//		(and their shadow variables)
	xor	a
	ioi	ld (PADR), a
	ld		(PADRShadow), a
	ioi	ld (PBDR), a
	ld		(PBDRShadow), a
	ioi	ld (PCDR), a
	ld		(PCDRShadow), a

	ioi	ld	(PDDDR),a
	ld		(PDDDRShadow),a
	ioi	ld (PDDR), a
	ld		(PDDRShadow), a
	ioi	ld (PDFR), a
	ld		(PDFRShadow), a
	ioi	ld (PDDCR), a
	ld		(PDDCRShadow), a
	ioi	ld	(PEDDR),a
	ld		(PEDDRShadow),a
	ioi	ld (PEDR), a
	ld		(PEDRShadow), a
	ioi	ld (PEFR), a
	ld		(PEFRShadow), a

	ioi	ld (TBCSR), a
	ld		(TBCSRShadow), a
	ioi	ld (TBCR), a
	ioi	ld (TBCRShadow), a
	
	// initialize shadow variables for registers that come up in
	// known states (and haven't been set by the BIOS already)
	xor	a
	ld		(SPCRShadow), a
	ld		(PDCRShadow), a
	ld		(PECRShadow), a
	ld		(IB0CRShadow), a
	ld		(IB1CRShadow), a
	ld		(IB2CRShadow), a
	ld		(IB3CRShadow), a
	ld		(IB4CRShadow), a
	ld		(IB5CRShadow), a
	ld		(IB6CRShadow), a
	ld		(IB7CRShadow), a
	ld		(I0CRShadow), a
	ld		(I1CRShadow), a
	ld		(TAT1RShadow), a
	ld		(TBCRShadow), a
	ld		(SBCRShadow), a
	ld		(SCCRShadow), a
	ld		(SDCRShadow), a
		
	// Ignore SMODE pins
	//  Dynamic C does this, but need to do it running stand alone too.
	ld    a,0x80
	ioi	ld (SPCR), a
	ld		(SPCRShadow), a

	// check for run mode		
	ioi ld a,(SPCR)
	and 60h
	cp  60h
	jr  nz,RunMode 
	; Reset 

dkLoop:
	call  bioshitwd
	ld 	hl,0
	ld 	(dkControlFlags+commAttn),hl          ; clear tables
	ld 	(dkControlFlags+breakLock),hl
	ld 	(dkControlFlags+watchReq),hl
	ld 	hl,dkControlFlags+keyReq
	ld 	(hl),0ffh      ; clear key request
	xor   a              ; 10-10-95
	ld 	hl,dkControlFlags+hardBreak
	ld    (hl), a        ; 10-10-95, 0 clear hard break flag
	inc   hl
	ld    (hl), a        ; 10-10-95, 0 clear doreset flag
	inc   hl
	ld    (hl), a        ; 10-10-95, 0 showmem
	inc   hl
	ld    (hl), a        ; 10-10-95, 0 spare
	ld 	hl,stepRelay
	ld 	de,dkBreakBP
	ld 	(hl),0c9h      ; ret
	inc   hl
	ld 	(hl),e
	inc   hl
	ld 	(hl),d     		; relay vector

	ipset 0
	call	dkBreakBP		; enter the debugger
   jp 	dkLoop			

RunMode:
	ipset 3
	call dkSetIntVecTabR       ;  disable debug RSTs
	ipset 0

	ld hl,OPMODE
	ld (hl),0x80
	jp StartUserCode	

;; This code repeatedly measures the timing on the 32kHz oscillator until
;; it matches twice in a row.  The 32kHz oscillator circuit could take as
;; long as 1.5 seconds to rise to a full voltage and we want to wait until
;; that is true...

WaitSettle::
	ld		de, 0000h				// first measurement value
	push	de							// save it for later
startmeas:
	ld		bc, 0000h				// our counter
	ld		de, 07FFh				// mask for RTC bits
wait_for_zero:
	ioi	ld (RTC0R), a			// load RTC registers
	ioi	ld hl, (RTC0R)			// read 1st two RTC registers
	and	hl, de					// mask off bits
	jr		nz, wait_for_zero		// repeat until all zero
timing_loop:
	inc	bc							// increment counter
	push	bc							// save counter
	ld		b, 057h					// empirically-derived loop counter
	ld		hl, WDTCR
delay_loop:
	ioi	ld	(hl), 05Ah			// hit watchdog
	djnz	delay_loop
	pop	bc							// restore counter
	ioi	ld (RTC0R), a			// load RTC registers
	ioi	ld hl, (RTC0R)			// read 1st two RTC registers
	bit	2, h						// test bit for 0800h
	jr		z, timing_loop			// if nonzero, keep looping
	
	ld		h, b						// h = upper nibble of counter
	ld		a, c						
	add	a, 08h					// (effectively rounding up)
	ld		l, a						// l = lower nibble of counter + 8
	rr		hl
	rr		hl
	rr		hl							// divide by 16
	rr		hl
	ld		a, l						// lower nibble is divisor!
	dec	a
	pop	de							// get last count
	cp		a, e						// compare last and current counts
	jr		z, donemeas				// if alike, done	
	ld		e, a
	push	de							// save this count
	jr		startmeas
donemeas:
	ret
	
dkInitTC::
	call	dkcInit					;	initialize comm module
	call	dkInitFcTable			;	initialize the 3-table
	call	dkInitControlFlags	;	initalize the control flags used by do28
	ret
		
	;	repeat trying until we read a byte from the receive buffer
dkReadAgain:
	call  bioshitwd
	call	dkReadProgPort
	jr		z,dkReadAgain

	;	repeat trying until we unload the byte to the transmit buffer
	ld		c,a
dkWriteAgain:
	call  bioshitwd
	call	dkWriteProgPort
	jr		nz,dkWriteAgain
		
	;	parallel port D, bit 0 goes to 0

dkWriteMem::
	// if log adr < DATAORG, use log Flash adr = phys adr
	// if log adr >= E000,   use phys adr with XPCval
	// if  DATAORG <= log adr < E000, use logical RAM addr
	ld    a,xpc
	push  af
	call  bioshitwd
	ld		a,(curHeader+address+1)

CheckXmem:
	cp		0xe0
	jr		c,ItsInRootRAM

ItsInXRAM:
	ld		a,(curHeader+XPCval)
	ld    xpc,a
ItsInRootRAM:
	push  ip
	ipset 1
	ld		hl,(curHeader+address)		;	destination
	ex		de,hl
	ld		hl,commBuffer					;	source
	ld		a,(curHeader+length)
	ld		b,0
	ld		c,a
moveByte:
	ld		a,(hl)
	ld		(de),a
	inc	hl
	inc	de
	dec	c
	jr		nz,moveByte
	pop ip
	pop   af
	ld    xpc,a
	ret

#endasm

#asm

dkSerialISR::
	;	serial interrupt handler
	push	af
	ex    af,af'
	push	af
	ld    a,xpc
	push	af
	push	bc
	push	de
	push	hl
	push  ix	
	
	call	dkcEntry				;	enter the FSM

	ioi 	ld a,(SASR)			;	check the status
	bit	SS_TPRG_BIT,a		;	transmit in progress bit
	jr		nz,.readyToExit	;	transmit in progress, don't disable it
	;	transmit is not in progress, clear the transmit buffer empty
	;	flag now

	ioi 	ld (SASR), a

.readyToExit:

	pop   ix		
	pop	hl
	pop	de
	pop	bc
	pop	af
	ld    xpc,a
	pop	af
	ex    af,af'
	pop	af
	ipres
	ret

dkReadProgPort::
	;	destroys A
	;	returns byte read (if any) in A
	;	returns with Z set if nothing is read
		
	;	check if there is anything available
	ioi 	ld a, (SASR)
	bit	SS_RRDY_BIT,a		;	if a received byte ready?
	ret	z						;	nope, return with z set
	;	otherwise, a byte *is* ready, read from data port
	ioi 	ld a, (SADR)
	ret							;	return with z *not* set

dkWriteProgPort::
	;	assumes byte to transmit is in C
	;	destroys A
	;	returns with Z reset if not transmitted
		
	;	check if the port is ready
	ioi 	ld a, (SASR)
	bit	SS_TFULL_BIT,a		;	can I transmit now?
	ret	nz						;	nope, return with nz set
	;	otherwise, the transmit buffer is ready, write to it!
	ld		a,c					;	move byte to transmit to a
	ioi 	ld (SADR), a
	ret							;	return with z *not* set

	nop
dkDCID:
	db "DynamiC"
dkProdName:
	db PRODUCT_NAME
dkInitFcTable::
	;	initialize the fctable here

;	zero out everything first
	ld		hl,fcTable
	ld		b,_fcTable+@LENGTH
	xor	a
dkInitFCClrByte:
	ld		(hl),a
	inc	hl
	djnz	dkInitFCClrByte
	
;struct _fcTable {
;	char DCID[7];			//	this field should contain "DynamiC"
	ld		hl,dkDCID				;	note that this DCID is name of the string
	ld		de,fcTable+DCID	;	note that this DCID is a field ID
	ld		bc,7
	ldir  
;	char majorRev;			//	major revision
	ld		a,0x02
	ld		(fcTable+majorRev),a
;	char minorRev;			//	minor revision
	ld		a,0x00
	ld		(fcTable+minorRev),a
;	char targetName[8];	//	name of target
	ld		hl,dkProdName			;	name of string
	ld		de,fcTable+targetName
	ld		bc,8
	ldir
;	void *symTable;		//	pointer to symbol table
	ld		hl,symTab			;	symbol table address
	ld		(fcTable+symTable),hl
;	unsigned checksum;	//	checksum for library
;	void *codeBase;		//	base of code area
	ld		hl,0x2000
	ld		(fcTable+codeBase),hl
;	void *dataTop;			//	top of code
	ld		hl,0xda00
	ld		(fcTable+dataTop),hl
;	void *dataBase;		//	base (bottom) of data
	ld		hl,0x2000
	ld		(fcTable+dataBase),hl
;	void *codeTop;			//	top of data
	ld		hl,0xd900
	ld		(fcTable+codeTop),hl
;### needs to be filed
;	void *dbgStack;		//	pointer to debug stack
	bool	hl					// set the stack from the current stack pointer
	ld		l,a
	add	hl,sp
	ld		(fcTable+dbgStack),hl	;	note that this is the field dkDbgStack
;	void *stepVector;		//	stepping breakpoint vector
	ld		hl,stepRelay ;INTVEC_BASE+RST28_OFS			;	stepRelay
	ld		(fcTable+stepVector),hl
;	char chDisStep;		//	character to stop stepping breakpoint
	ld		a,0xc9			;	code for return
	ld		(fcTable+chDisStep),a
;	char chEnbStep;		//	character to enable stepping breakpoint
	ld		a,0xc3			;	code for jp
	ld		(fcTable+chEnbStep),a
;	void *trapVector;		//	pointer to TRAP development vector
;	void *rst38Vector;	//	pointer to RST 38 development vector
;	void *PFVector;		//	pointer to powerfail vector
;	### requires changes, hard coded for now
	ld		hl,0x22f3
	ld		(fcTable+PFVector),hl
;	void *commTable;		//	pointer to communication table
	ld		hl,dkControlFlags+commPtr
	ld		(fcTable+commTable),hl
;	char commAttn;			//	communication attention flag
	ld		hl,dkControlFlags+commAttn
	ld		(hl),0
;	char ramSize;			//	size of ram in 4kbyte pages
;### requires changes, hard coded for now
//	call	CheckRamSize
	ld		a,RAM_SIZE ;			;	128kbyte RAM

	ld		(fcTable+ramSize),a
;	char memBreak;			//	CBAR value
;### requires changes, hard coded for now
	ld		a,HW_MEMBREAK			;	typical EPROM/RAM break
	ld		(fcTable+memBreak),a
;	void *nextBankV;		//	next bank vector
;	void *biosEnd;			//	end of BIOS
	ld		hl,dkEnd
	ld		(fcTable+biosEnd),a
;	char xcodeTop;			//	top of xmem code
;this field doesn't seem to be used?
;	char ramStart;			//	start address of RAM in 4kbyte pages
;### requires changes, hard coded for now
	ld		a,RAM_START			;	typical RAM mapping
	ld		(fcTable+ramStart),a
   ld 	hl, _xexit
   ld    (DCParam+errorExit), hl  ; initialize error exit
	ret
#define ERROR_EXIT DCParam+errorExit
bioshitwd::
	push  af
	ld    a, 0x5a
	ioi 	ld (WDTCR),a	
	pop  af
	ret
#endasm

#asm
dkDoMsg::
.waitFlagClear:
	ld		a,(dkControlFlags+commAttn)
	or		a
	jr		nz, .waitFlagClear

	push	ip
	ipset	1
	;	flag is now cleared
	ld		de, stdioCommBuff+4
	ld		bc,0

	; store the new print flag
	ld		a,(NewPrintConFlag)
	ld		(fcTable+PrintToCon),a	
	
.chkEOM:
	ld		a,(hl)
	or		a
	jr		z,.foundEOM

	ld		(de),a
	inc	hl
	inc	de
	inc	bc
	jr		.chkEOM

.foundEOM:
	ld		(stdioCommBuff),bc

	ld		a,1
	ld		(dkControlFlags+commAttn),a

	ld		hl,(dkControlFlags+commPtr) 
   pop   ip
	ret

#endasm

#asm
__bp_init::
dkBPInit::
	ld		hl, (fcTable+chDisStep) ; Get Enable/Disable Bytes
	ld 	(_dkdisable28),hl   ; disable byte and enable byte
	ld		hl,	stepRelay ;(fcTable+stepVector)
	ld 	a,	(_dkenable28)
	ld		(hl),	a							;	enable break point
	ld 	hl,	DCSrcDebug+fEntryCount      ; Pointer to Control
	ld 	(hl),	0      ; Disable Control Initially
	ld	 	de,	DCSrcDebug+nestCount		;	some convention used by do18?
	rst 18h
#endasm

#asm
_xexit2::
	rst	18h
	ipset 3
	jp		_xexit2

_xexit::
	rst	18h
	ipset 3
	ld    a,0x53
	ioi   ld (WDTCR),a
_xexitLoop:
	jp		_xexitLoop
#endasm

#asm
	
dkSetIntVecTabP::	 ; Program mode
	;	set up interrupt vector table
	ld		a,0xff & (INTVEC_BASE >> 8)	;
	ld		iir,a
	ld		a,0xff & (XINTVEC_BASE >> 8)	;
	ld		eir,a
	ld		a,0xc3		;	this is the jump instruction
	ld		(INTVEC_BASE+RST18_OFS),a		;	all are relays
	ld		(INTVEC_BASE+RST20_OFS),a
	ld		(INTVEC_BASE+RST28_OFS),a
	ld		hl,dkSoftBP
	ld		(INTVEC_BASE+RST18_OFS+1),hl
	ld		hl,dkHardBP
	ld		(INTVEC_BASE+RST20_OFS+1),hl
	ld		hl,stepRelay;dkBreakBP
	ld		(INTVEC_BASE+RST28_OFS+1),hl
	ld    hl,dkBreakBP 
	ld    (stepRelay+1),hl
	ld    a,0c3h
	ld    (stepRelay),a
	ret

dkSetIntVecTabR::   ; Runmode
	;	set up interrupt vector table
	ld		a,0xff & (INTVEC_BASE >> 8)	;
	ld		iir,a
	ld		a,0xff & (XINTVEC_BASE >> 8)	;
	ld		eir,a
	ld		a,0xc9		;	this is the ret instruction
	ld		(INTVEC_BASE+RST18_OFS),a		;	all are relays
	ld		(INTVEC_BASE+RST20_OFS),a
	ld		(INTVEC_BASE+RST28_OFS),a
	ret

; .startup/dkStartup
; code to run each time the program executes
; initializes the stack allocation 
;
dkStartup::	
	pop hl
   jp	(hl)					; jump to old return address
	
#endasm

//#flushlib

#asm

dkEnd::
__xexit2:: jp _xexit2
__xexit::  jp _xexit
#endasm

#flushlib

#asm
symTab::
	dw		symsize

	dw RAM_START
	db 0
	db "IOP_RAM_STAR",'T'+0x80

	dw DATASEGVAL
	db 0
	db "IOP_DATASEGVA",'L'+0x80
	
	dw RAM_SIZE
	db 0
	db "IOP_RAM_SIZ",'E'+0x80
	
	dw INTVEC_BASE
	db 0
	db "IOP_INTVEC_BAS",'E'+0x80
	
	dw FLASH_SIZE
	db 0
	db "IOP_FLASH_SIZ",'E'+0x80

	dw DATAORG
	db 0
	db "IOP_DATAOR",'G'+0x80

	dw STACKORG
	db 0
	db "IOP_STACKOR",'G'+0x80

	dw OPMODE
	db 0
	db "OPMOD",'E'+0x80

	dw		__xexit2
	db		0
	db		"..exit",'2'+0x80

	dw		_xexit
	db		0
	db		"exi",'t'+0x80

	dw		__xexit
	db		0
	db		".exi",'t'+0x80
	
	dw		_xexit
	db		0
	db		".exit",'2'+0x80

AUX_STACK_LIMIT:: EQU DCParam+auxStackLimit

AUX_STACK_PTR:: EQU DCParam+auxStackPtr

STACK_LIMIT::	EQU DCParam+stackLimit

	dw		DCParam+rst28Swt
	db		0
	db		"RST28SW",'T'+0x80

	dw		DCParam+rst28SwtOff
	db		0
	db		"RST28SWT_OF",'F'+0x80

	dw		dkStartup
	db		0
	db		".startu",'p'+0x80

	dw dkBPInit
	db	0
	db	"..bp_ini",'t'+0x80

_store_ID_Block_Size::
	dw 0xffff
	db	0
	db	"_ID_BLOCK_SIZE",'_'+0x80

#endasm

//#flushlib

//	we need to end the symbol table now
#asm
	dw	0		;	indicates end of symbol table
	db	0

symTabEnd::
symsize: equ symTabEnd-symTab-2
#endasm


// include bios C support libraries
#use default.h

//!!!Do NOT insert code between here and #pragma CompileProgram!!!
//#flushlib
#asm
BIOSCodeEnd:
StartUserCode::
#endasm
#pragma CompileProgram
